package modbus

import (
	"fmt"
	"log"
	"math/rand"
	"sync"
	"time"

	"github.com/tbrandon/mbserver"
)

type ModbusServer struct {
	server     *mbserver.Server
	isRunning  bool
	isPaused   bool
	updateLock sync.Mutex
}

func NewModbusServer() *ModbusServer {
	return &ModbusServer{
		server: mbserver.NewServer(),
	}
}
func (ms *ModbusServer) Start() error {
	ms.updateLock.Lock()
	defer ms.updateLock.Unlock()

	if ms.isRunning {
		return fmt.Errorf("server is already running")
	}

	err := ms.server.ListenTCP("0.0.0.0:502")
	if err != nil {
		return err
	}

	ms.isRunning = true
	ms.isPaused = false

	go ms.updateData()

	log.Println("Modbus TCP server started")
	return nil
}

func (ms *ModbusServer) Stop() error {
	ms.updateLock.Lock()
	defer ms.updateLock.Unlock()

	if !ms.isRunning {
		return fmt.Errorf("server is not running")
	}

	ms.server.Close()

	ms.isRunning = false
	ms.isPaused = false

	log.Println("Modbus TCP server stopped")
	return nil
}

func (ms *ModbusServer) Pause() error {
	ms.updateLock.Lock()
	defer ms.updateLock.Unlock()

	if !ms.isRunning {
		return fmt.Errorf("server is not running")
	}

	if ms.isPaused {
		return fmt.Errorf("server is already paused")
	}

	ms.isPaused = true
	log.Println("Modbus TCP server paused")
	return nil
}

func (ms *ModbusServer) Resume() error {
	ms.updateLock.Lock()
	defer ms.updateLock.Unlock()

	if !ms.isRunning {
		return fmt.Errorf("server is not running")
	}

	if !ms.isPaused {
		return fmt.Errorf("server is not paused")
	}

	ms.isPaused = false
	log.Println("Modbus TCP server resumed")
	return nil
}

func (ms *ModbusServer) updateData() {
	for ms.isRunning {
		if !ms.isPaused {
			ms.updateLock.Lock()
			for i := 0; i < 10; i++ {
				temperature := rand.Float32()*30 + 10 // 10-40°C
				humidity := rand.Float32()*60 + 20    // 20-80%
				doorStatus := rand.Intn(2) == 1       // 0 or 1

				ms.server.HoldingRegisters[i*3] = uint16(temperature * 100)
				ms.server.HoldingRegisters[i*3+1] = uint16(humidity * 100)
				if doorStatus {
					ms.server.HoldingRegisters[i*3+2] = 1
				} else {
					ms.server.HoldingRegisters[i*3+2] = 0
				}
			}
			ms.updateLock.Unlock()
		}
		time.Sleep(1 * time.Second)
	}
}

func (ms *ModbusServer) GetData() []map[string]interface{} {
	ms.updateLock.Lock()
	defer ms.updateLock.Unlock()

	data := make([]map[string]interface{}, 10)
	for i := 0; i < 10; i++ {
		temperature := float32(ms.server.HoldingRegisters[i*3]) / 100.0
		humidity := float32(ms.server.HoldingRegisters[i*3+1]) / 100.0
		doorStatus := ms.server.HoldingRegisters[i*3+2] == 1

		data[i] = map[string]interface{}{
			"id":          i + 1,
			"temperature": temperature,
			"humidity":    humidity,
			"doorStatus":  doorStatus,
		}
	}
	return data
}
